<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>山工院校园数字地图</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 先引入 Leaflet 主库 -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>

    <!-- geometryutil 必须在 leaflet.js 之后、leaflet.pm 之前 -->
    <script src="https://unpkg.com/leaflet-geometryutil"></script>
    <!-- 国内备用：<script src=\"https://cdn.bootcdn.net/ajax/libs/leaflet-geometryutil/0.10.0/leaflet.geometryutil.min.js\"></script> -->

    <!-- 再引入插件和工具库 -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine/dist/leaflet-routing-machine.css" />
    <script src="https://unpkg.com/leaflet-routing-machine/dist/leaflet-routing-machine.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" />
    <script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
    <script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
    <!-- 引入 leaflet.pm CSS/JS -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet.pm@latest/dist/leaflet.pm.css" />
    <script src="https://unpkg.com/leaflet.pm@latest/dist/leaflet.pm.min.js"></script>
    <style>
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
        }
        body {
            display: flex;
            flex-direction: column;
            min-height: 100vh;
            background: #fafbfc;
        }
        #main-container {
            display: flex;
            flex-direction: row;
            justify-content: center;
            align-items: flex-start;
            width: 100vw;
            max-width: 100vw;
            height: 80vh;
            min-height: 500px;
        }
        #map {
            height: 100%;
            min-height: 400px;
            width: 70vw;
            min-width: 500px;
            max-width: 900px;
            border-radius: 12px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.08);
        }
        #side-panel {
            width: 320px;
            min-width: 220px;
            margin-left: 18px;
            display: flex;
            flex-direction: column;
            align-items: stretch;
            justify-content: center;
            height: 100%;
            gap: 14px;
        }
        #chart {
            width: 100%;
            height: 260px;
            background: #fff;
            border-radius: 12px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.08);
            padding: 10px;
            margin-top: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #bufferBtn {
            margin: 12px 0 0 0;
            background: #43a047;
            color: #fff;
            border: none;
            border-radius: 8px;
            padding: 7px 18px;
            font-size: 15px;
            cursor: pointer;
            box-shadow: 0 2px 8px rgba(0,0,0,0.08);
        }
        #bufferBtn:hover { background: #2e7031; }
        #deleteBufferBtn {
            margin: 12px 0 0 0;
            background: #e5395b;
            color: #fff;
            border: none;
            border-radius: 8px;
            padding: 7px 18px;
            font-size: 15px;
            cursor: pointer;
            box-shadow: 0 2px 8px rgba(0,0,0,0.08);
            display: none;
        }
        #deleteBufferBtn:hover { background: #ad1457; }
        @media (max-width: 900px) {
            #main-container { flex-direction: column; align-items: center; height: auto; }
            #map { width: 95vw; min-width: 0; max-width: 100vw; height: 350px; }
            #side-panel { width: 95vw; min-width: 0; margin-left: 0; }
        }
        /* 合并弹窗样式 */
        .modal {
          position: fixed; z-index: 2000; left: 0; top: 0; width: 100vw; height: 100vh;
          background: rgba(0,0,0,0.18); display: none; justify-content: center; align-items: center;
        }
        .modal-content {
          background: #fff; border-radius: 14px; box-shadow: 0 4px 24px rgba(0,0,0,0.10);
          padding: 24px 28px; min-width: 320px; max-width: 90vw; display: flex; flex-direction: column;
        }
        .modal-title {
          font-size: 18px; font-weight: bold; margin-bottom: 12px; color: #223354;
        }
        .modal-body {
          font-size: 15px; color: #444; margin-bottom: 16px;
        }
        .modal-footer {
          text-align: right;
        }
        .modal-btn {
          padding: 7px 28px; border: none; border-radius: 8px; font-size: 15px; font-weight: bold; cursor: pointer;
          margin-right: 8px; background: #295bff; color: #fff;
        }
        .modal-btn.cancel { background: #f2f4f8; color: #666; }
        /* 测量label样式 */
        .measure-label-tooltip {
            background: rgba(255,255,255,0.95);
            color: #1976d2;
            border-radius: 6px;
            padding: 2px 10px;
            font-weight: bold;
            border: 1px solid #1976d2;
            font-size: 14px;
            box-shadow: 0 1px 4px rgba(0,0,0,0.08);
        }
        
        /* 路由控制面板样式 */
        .leaflet-routing-container {
            background: white;
            border-radius: 8px;
            box-shadow: 0 4px 16px rgba(0,0,0,0.15);
            border: 1px solid #ddd;
            max-width: 320px;
            min-width: 280px;
        }
        
        .leaflet-routing-container h2 {
            background: #2196f3;
            color: white;
            margin: 0;
            padding: 12px 16px;
            font-size: 16px;
            border-radius: 8px 8px 0 0;
            text-align: center;
        }
        
        .leaflet-routing-container h3 {
            margin: 8px 0;
            font-size: 14px;
            color: #333;
        }
        
        .leaflet-routing-container input {
            width: 100%;
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 14px;
            margin-bottom: 8px;
            box-sizing: border-box;
        }
        
        .leaflet-routing-container input:focus {
            outline: none;
            border-color: #2196f3;
            box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.2);
        }
        
        /* 确定按钮样式 */
        .routing-confirm-btn {
            width: 100%;
            background: #2196f3;
            color: white;
            border: none;
            border-radius: 6px;
            padding: 10px 16px;
            font-size: 14px;
            font-weight: bold;
            cursor: pointer;
            margin: 8px 0;
            transition: background 0.2s;
        }
        
        .routing-confirm-btn:hover {
            background: #1976d2;
        }
        
        .routing-confirm-btn:disabled {
            background: #ccc;
            cursor: not-allowed;
        }
        
        .leaflet-routing-container .leaflet-routing-alt {
            max-height: 200px;
            overflow-y: auto;
            border-top: 1px solid #eee;
            margin-top: 8px;
        }
        
        .leaflet-routing-container .leaflet-routing-alt h3 {
            background: #f5f5f5;
            padding: 8px 12px;
            margin: 0;
            font-size: 13px;
            color: #666;
        }
        
        .leaflet-routing-container .leaflet-routing-alt h4 {
            margin: 4px 0;
            font-size: 12px;
            color: #333;
            padding: 0 12px;
        }
        
        .leaflet-routing-container .leaflet-routing-alt h4:first-child {
            margin-top: 8px;
        }
        
        /* 路由按钮样式 */
        .routing-button:hover, .quick-routing-button:hover {
            background: #f0f0f0 !important;
            border-color: #2196f3 !important;
        }
        
        /* 起终点标记样式 */
        .start-marker, .end-marker {
            z-index: 1000;
        }
        
        /* 路由线路样式 */
        .leaflet-routing-alt-routes {
            background: #e3f2fd;
            border-radius: 4px;
            margin: 4px 8px;
            padding: 8px;
        }
        
        /* 空间分析按钮样式 */
        .analysis-btn {
            width: 100%;
            margin: 6px 0;
            background: #4caf50;
            color: #fff;
            border: none;
            border-radius: 6px;
            padding: 8px 12px;
            font-size: 14px;
            cursor: pointer;
            transition: all 0.2s;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .analysis-btn:hover {
            background: #388e3c;
            transform: translateY(-1px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.15);
        }
        .analysis-btn.active {
            background: #ff9800;
            box-shadow: 0 0 0 2px rgba(255, 152, 0, 0.3);
        }
        
        /* 分析结果面板样式 */
        .analysis-panel {
            position: absolute;
            top: 10px;
            right: 10px;
            background: white;
            border-radius: 8px;
            box-shadow: 0 4px 16px rgba(0,0,0,0.15);
            padding: 15px;
            max-width: 300px;
            max-height: 400px;
            overflow-y: auto;
            z-index: 1000;
            display: none;
        }
        .analysis-panel h4 {
            margin: 0 0 10px 0;
            color: #2196f3;
            font-size: 16px;
        }
        .analysis-panel .result-item {
            margin: 8px 0;
            padding: 8px;
            background: #f5f5f5;
            border-radius: 4px;
            font-size: 13px;
        }
        .analysis-panel .close-btn {
            position: absolute;
            top: 5px;
            right: 10px;
            background: none;
            border: none;
            font-size: 18px;
            cursor: pointer;
            color: #666;
        }
        /* 地图左下角图例控件样式 */
        .leaflet-control.legend {
            background: white;
            padding: 12px 18px 12px 18px;
            border-radius: 10px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.10);
            border: 1px solid #ccc;
            font-size: 15px;
            min-width: 120px;
            max-width: 260px;
            word-break: break-all;
            white-space: normal;
            line-height: 1.7;
            margin-bottom: 18px;
        }
        .legend-title {
            font-weight: bold;
            font-size: 16px;
            margin-bottom: 8px;
        }
        .legend-item {
            display: flex;
            align-items: center;
            margin-bottom: 4px;
        }
        .legend-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            display: inline-block;
            margin-right: 7px;
            border: 2px solid #fff;
            box-shadow: 0 1px 2px rgba(0,0,0,0.08);
        }
        .legend-dot.canteen { background: #e91e63; }
        .legend-dot.dorm { background: #ff9800; }
        .legend-dot.teach { background: #4caf50; }
        .legend-dot.start-custom { background: #009688; border:2px solid #00695c; }
        .legend-dot.end-custom { background: #d32f2f; border:2px solid #b71c1c; }
        .legend-line { display:inline-block;width:28px;height:0;border-top:4px dashed #8e24aa;vertical-align:middle;margin:0 7px 0 0; }
        .legend-label { font-size: 14px; color: #333; }
    </style>
</head>
<body>
    <h2 style="text-align:center;">山工院校园数字地图</h2>
    <div id="main-flex" style="display:flex;justify-content:center;align-items:flex-start;gap:32px;flex-wrap:wrap;margin-top:24px;">
      <div id="main-container">
        <div id="map"></div>
        <div id="side-panel">
          <button id="addMarkerBtn" style="margin:10px 0 0 0;background:#1976d2;color:#fff;border:none;border-radius:8px;padding:7px 18px;font-size:15px;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.08);">+ 添加标记</button>
          <button id="bufferBtn">缓冲区分析</button>
          <button id="deleteBufferBtn">删除缓冲区</button>
          <button id="quickSetBtn">📍 快速设置起终点</button>
          <button id="clearRouteBtn" style="margin:6px 0 0 0;background:#ff9800;color:#fff;border:none;border-radius:8px;padding:7px 18px;font-size:15px;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.08);">🗑️ 清除路径</button>
          <button id="siteAnalysisBtn" style="margin:12px 0 0 0;background:#4caf50;color:#fff;border:none;border-radius:8px;padding:7px 18px;font-size:15px;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.08);">选址分析</button>
          <div id="chart"></div>
          <div id="dormDeptChart" style="width:100%;min-width:0;height:260px;background:#fff;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,0.08);padding:4px;margin-top:24px;"></div>
        </div>
      </div>
      <div id="feature-desc" style="width:540px;min-width:320px;max-width:560px;padding:12px 6px 8px 6px;background:#fff;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,0.08);font-size:13.5px;color:#333;line-height:1.5;margin:0;display:flex;flex-direction:row;justify-content:space-between;gap:12px;text-align:left;">
        <div style="flex:1 1 0;min-width:0;">
          <b style="font-size:14px;display:block;margin-bottom:4px;">地图与标记</b>
          <ul style="padding-left:14px;margin:0;">
            <li>地图浏览、缩放、点选</li>
            <li>添加/删除自定义标记</li>
            <li>缓冲区分析</li>
          </ul>
        </div>
        <div style="flex:1 1 0;min-width:0;">
          <b style="font-size:14px;display:block;margin-bottom:4px;">空间分析与统计</b>
          <ul style="padding-left:14px;margin:0;">
            <li>测量工具（距离、面积）</li>
            <li>统计图表（男女比例、宿舍分布）</li>
            <li>选址分析（新建教学楼等多因素定点）</li>
            <li>支持编辑和删除</li>
          </ul>
        </div>
        <div style="flex:1 1 0;min-width:0;">
          <b style="font-size:14px;display:block;margin-bottom:4px;">路径与交互</b>
          <ul style="padding-left:14px;margin:0;">
            <li>路径规划（虚线路径/最短路径）</li>
            <li>起点深绿，终点深红</li>
            <li>界面自适应，控件/弹窗/图例中文</li>
          </ul>
        </div>
      </div>
    </div>
    <!-- 通用弹窗 -->
    <div id="customModal" class="modal">
      <div class="modal-content">
        <div class="modal-title" id="modalTitle"></div>
        <div class="modal-body" id="modalBody"></div>
        <div class="modal-footer" id="modalFooter"></div>
      </div>
    </div>
    <!-- 分析结果面板 -->
    <div id="analysisPanel" class="analysis-panel">
        <button class="close-btn" onclick="closeAnalysisPanel()">×</button>
        <h4 id="analysisTitle">分析结果</h4>
        <div id="analysisContent"></div>
    </div>
    <!-- 选择出行方式弹窗（合并到通用弹窗，不再单独保留） -->
    <script>
        // 初始化地图，设置中心点和缩放级别
        var map = L.map('map').setView([35.0, 112.0], 16); // 这里的经纬度请替换为你学校的实际坐标

        // 添加底图（OpenStreetMap 明亮风格）
        L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
            maxZoom: 19,
            attribution: '© OpenStreetMap & CartoDB'
        }).addTo(map);

        // 示例：添加一个标记点
        L.marker([35.0, 112.0]).addTo(map)
            .bindPopup('这里是山工院')
            .openPopup();

        L.marker([35.0005, 112.0005]).addTo(map)
          .bindPopup('图书馆');

        // 加载本地 GeoJSON 数据（校园建筑/范围等）
        fetch('../data/campus.geojson')
          .then(response => response.json())
          .then(data => {
            L.geoJSON(data, {
              style: function(feature) {
                let color = "#3388ff";
                if (feature.properties && feature.properties.type) {
                  if (feature.properties.type === "教学楼") color = "#4caf50";
                  if (feature.properties.type === "宿舍") color = "#ff9800";
                  if (feature.properties.type === "食堂") color = "#e91e63";
                }
                return {
                  color: color,
                  weight: 3,
                  fillColor: color,
                  fillOpacity: 0.4
                };
              },
              pointToLayer: function(feature, latlng) {
                return L.circleMarker(latlng, {
                  radius: 8,
                  fillColor: "#ff7800",
                  color: "#fff",
                  weight: 2,
                  opacity: 1,
                  fillOpacity: 0.9
                });
              },
              onEachFeature: function (feature, layer) {
                if (feature.properties && feature.properties.name) {
                  let popupContent = '<div style="font-weight:bold;font-size:18px;margin-bottom:8px;">' + feature.properties.name + '</div>';
                  if (feature.properties.type) {
                    popupContent += '<div style="color:#555;font-size:15px;margin-bottom:4px;">类型：' + feature.properties.type + '</div>';
                  }
                  layer.bindPopup(popupContent);
                }
              }
            }).addTo(map);
          });

        // 加载并展示data/Export_Output.json中的GeoJSON点数据（自动分类并美化）
        fetch('../data/Export_Output.json')
          .then(response => response.json())
          .then(data => {
            // 分类颜色和图例
            const typeColor = {
              '食堂': '#e5395b',
              '宿舍': '#ff9800',
              '教学楼': '#43a047',
              '其他': '#3388ff'
            };
            const typeName = ['食堂', '宿舍', '教学楼', '其他'];
            let typeSet = new Set();
            // 分类函数
            function getType(feature) {
              const f8 = feature.properties && feature.properties.Field8 ? feature.properties.Field8 : '';
              if (f8.includes('餐饮') || f8.includes('食堂') || f8.includes('餐厅')) return '食堂';
              if (f8.includes('宿舍')) return '宿舍';
              if (f8.includes('教学楼') || f8.includes('学校') || f8.includes('图书馆')) return '教学楼';
              return '其他';
            }
            // 图层
            window.geoLayer = L.geoJSON(data, {
              pointToLayer: function(feature, latlng) {
                const type = getType(feature);
                typeSet.add(type);
                return L.circleMarker(latlng, {
                  radius: 10,
                  fillColor: typeColor[type],
                  color: '#fff',
                  weight: 2,
                  opacity: 1,
                  fillOpacity: 0.95
                });
              },
              onEachFeature: function(feature, layer) {
                let popupContent = '';
                if (feature.properties && feature.properties.Field1) {
                  popupContent += '<div style="font-weight:bold;font-size:15px;margin-bottom:4px;line-height:1.2;">' + feature.properties.Field1 + '</div>';
                }
                if (feature.properties && feature.properties.Field2) {
                  popupContent += '<div style="color:#555;font-size:13px;">' + feature.properties.Field2 + '</div>';
                }
                layer.bindPopup(popupContent);
              }
            }).addTo(map);
            // 自动缩放到所有点
            map.fitBounds(window.geoLayer.getBounds());
            // 动态生成图例
            let legendHtml = '<b>图例</b><br>';
            typeName.forEach(type => {
              if (typeSet.has(type)) {
                legendHtml += `<span style=\"color:${typeColor[type]};font-size:18px;\">●</span> ${type}<br>`;
              }
            });
          });

        // 增加比例尺控件
        L.control.scale().addTo(map);

        // 用户标记点类型和颜色
        const userTypeColor = {
          '食堂': '#e5395b',
          '宿舍': '#ff9800',
          '教学楼': '#43a047',
          '其他': '#3388ff'
        };

        // 用户添加的标记点数据
        var userMarkers = [];
        var userMarkerData = [];
        // 移除原有 map.on('click', ...) 的全局监听
        // map.on('click', ...); // 已删除

        // 添加标记模式
        var addMarkerMode = false;
        var addMarkerClickHandler = function(e) {
          var latlng = e.latlng;
          showInputDialog('请输入标记点名称（可选）：', {}, function(result) {
            if (result !== null) {
              var marker = L.circleMarker(latlng, {
                radius: 10,
                fillColor: userTypeColor[result.type],
                color: '#fff',
                weight: 2,
                opacity: 1,
                fillOpacity: 0.95
              }).addTo(map);
              userMarkers.push(marker);
              userMarkerData.push({name: result.name, type: result.type, marker: marker});
              updateMarkerPopup(userMarkers.length - 1);
              marker.on('drag', function() {}); // circleMarker不支持拖动
            }
            // 退出添加标记模式
            map.off('click', addMarkerClickHandler);
            addMarkerMode = false;
            document.getElementById('addMarkerBtn').innerText = '+ 添加标记';
            document.getElementById('addMarkerBtn').disabled = false;
          });
        };
        document.getElementById('addMarkerBtn').onclick = function() {
          if (addMarkerMode) return;
          addMarkerMode = true;
          this.innerText = '请在地图上点选位置...';
          this.disabled = true;
          map.on('click', addMarkerClickHandler);
        };
        // 更新弹窗内容（风格统一）
        function updateMarkerPopup(idx) {
          var marker = userMarkers[idx];
          var data = userMarkerData[idx];
          var popupContent = '';
          if (data.name) popupContent += '<div style="font-weight:bold;font-size:15px;margin-bottom:4px;line-height:1.2;">' + data.name + '</div>';
          popupContent += '<div style="color:#555;font-size:13px;margin-bottom:4px;">' + data.type + '</div>';
          popupContent += '<div style="display:flex;gap:6px;justify-content:center;">';
          popupContent += '<button onclick="window.modifyMarker(' + idx + ')" style="background:#43a047;color:#fff;border:none;border-radius:8px;padding:3px 14px;cursor:pointer;font-size:13px;transition:background 0.2s;line-height:1.2;" onmouseover="this.style.backgroundColor=\'#2e7031\'" onmouseout="this.style.backgroundColor=\'#43a047\'">修改</button>';
          popupContent += '<button onclick="window.deleteMarker(' + idx + ')" style="background:#e5395b;color:#fff;border:none;border-radius:8px;padding:3px 14px;cursor:pointer;font-size:13px;transition:background 0.2s;line-height:1.2;" onmouseover="this.style.backgroundColor=\'#ad1457\'" onmouseout="this.style.backgroundColor=\'#e5395b\'">删除</button>';
          popupContent += '</div>';
          marker.bindPopup(popupContent).openPopup();
        }
        window.deleteMarker = function(idx) {
          if (userMarkers[idx]) {
            map.removeLayer(userMarkers[idx]);
            userMarkers[idx] = null;
            userMarkerData[idx] = null;
          }
        };
        window.modifyMarker = function(idx) {
          if (userMarkers[idx]) {
            showInputDialog('请输入新的标记点名称：', userMarkerData[idx], function(result) {
              if (result !== null) {
                userMarkerData[idx].name = result.name;
                userMarkerData[idx].type = result.type;
                userMarkers[idx].setStyle({fillColor: userTypeColor[result.type]});
                updateMarkerPopup(idx);
              }
            }, userMarkerData[idx].type);
          }
        };
        // 自定义输入弹窗逻辑（支持类型选择）
        function showInputDialog(label, defaultValue, callback, defaultType) {
          document.getElementById('modalTitle').innerText = label;
          var input = document.getElementById('modalBody');
          var typeSel = document.getElementById('modalType');
          input.value = defaultValue && defaultValue.name ? defaultValue.name : '';
          typeSel.value = defaultValue && defaultValue.type ? defaultValue.type : (defaultType || '其他');
          document.getElementById('customModal').style.display = 'flex';
          input.focus();
          function close(result) {
            document.getElementById('customModal').style.display = 'none';
            document.getElementById('modalOk').onclick = null;
            document.getElementById('modalCancel').onclick = null;
            input.onkeydown = null;
            callback(result);
          }
          document.getElementById('modalOk').onclick = function() {
            close({name: input.value, type: typeSel.value});
          };
          document.getElementById('modalCancel').onclick = function() {
            close(null);
          };
          input.onkeydown = function(e) {
            if (e.key === 'Enter') close({name: input.value, type: typeSel.value});
            if (e.key === 'Escape') close(null);
          };
        }

        // 缓冲区分析
        var bufferLayer = null;
        document.getElementById('bufferBtn').onclick = function() {
          alert('请在地图上点击选择缓冲区中心点');
          var onceClick = function(e) {
            var latlng = e.latlng;
            var radius = prompt('请输入缓冲半径（米）：', 100);
            if (radius && !isNaN(radius)) {
              var pt = turf.point([latlng.lng, latlng.lat]);
              var buffered = turf.buffer(pt, Number(radius), {units: 'meters'});
              if (bufferLayer) map.removeLayer(bufferLayer);
              bufferLayer = L.geoJSON(buffered, {
                style: {color:'#e5395b', fillColor:'#e57373', fillOpacity:0.25, weight:2}
              }).addTo(map);
              document.getElementById('deleteBufferBtn').style.display = 'block';
            }
            map.off('click', onceClick);
          };
          map.on('click', onceClick);
        };
        document.getElementById('deleteBufferBtn').onclick = function() {
          if (bufferLayer) {
            map.removeLayer(bufferLayer);
            bufferLayer = null;
          }
          document.getElementById('deleteBufferBtn').style.display = 'none';
        };

        // 统计图表（ECharts演示）
        var chartDom = document.getElementById('chart');
        var myChart = echarts.init(chartDom);
        var option = {
          title: { text: '宿舍楼男女比例', left: 'center', top: 10, textStyle: {fontSize: 18} },
          tooltip: { trigger: 'item', formatter: '{b}: {c}人 ({d}%)' },
          legend: { orient: 'vertical', left: 'left', data: ['男生', '女生'] },
          series: [
            {
              name: '人数',
              type: 'pie',
              radius: '60%',
              data: [
                { value: 320, name: '男生' },
                { value: 280, name: '女生' }
              ],
              emphasis: {
                itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' }
              },
              label: { formatter: '{b}: {c}人 ({d}%)' }
            }
          ]
        };
        myChart.setOption(option);

        // 各系学生宿舍楼人口分布图（ECharts柱状图）
        var dormDeptDom = document.getElementById('dormDeptChart');
        var dormDeptChart = echarts.init(dormDeptDom);
        var dormDeptOption = {
          title: { text: '各系学生宿舍楼人口分布', left: 'center', top: 10, textStyle: {fontSize: 18} },
          tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
          grid: { left: 40, right: 20, bottom: 48, top: 50 },
          xAxis: { type: 'category', data: ['计算机', '土木', '机械', '电气', '管理', '艺术'], axisLabel: { fontSize: 13, interval: 0 } },
          yAxis: { type: 'value', name: '人数', axisLabel: { fontSize: 13 } },
          series: [{
            name: '人数',
            type: 'bar',
            data: [120, 98, 135, 110, 80, 60],
            itemStyle: { color: '#43a047', borderRadius: [6,6,0,0] },
            label: { show: true, position: 'top', fontSize: 13 }
          }]
        };
        dormDeptChart.setOption(dormDeptOption);
        // 强制初次resize，防止被裁剪
        dormDeptChart.resize();
        // 自适应窗口大小
        window.addEventListener('resize', function() {
          dormDeptChart.resize();
        });

        // 汉化 leaflet.pm 工具栏（addControls前，建议锁定@latest版本）
        if (window.L && window.L.PM && window.L.PM.setLang) {
          L.PM.setLang('zh', {
            tooltips: {
              placeMarker: '点击地图添加点',
              firstVertex: '点击地图添加第一个点',
              continueLine: '点击地图继续画线',
              finishLine: '双击或点击最后一个点完成',
              finishPoly: '双击或点击第一个点完成',
              finishRect: '点击完成',
              finishCircle: '点击完成',
              finishCut: '点击完成裁剪',
              edit: '拖动点编辑形状',
              drag: '拖动图形',
              cut: '点击地图绘制裁剪区域',
              removal: '点击图形删除'
            },
            actions: {
              finish: '完成',
              cancel: '取消',
              removeLastVertex: '撤销上一个点'
            },
            buttonTitles: {
              drawMarkerButton: '添加标记点',
              drawPolyButton: '绘制多边形',
              drawLineButton: '绘制折线',
              drawCircleButton: '绘制圆',
              drawRectButton: '绘制矩形',
              editButton: '编辑图形',
              dragButton: '拖动图形',
              cutButton: '裁剪图形',
              removalButton: '删除图形'
            }
          });
          map.pm.setLang('zh');
        }
        // 集成 leaflet.pm 测量工具（支持测距、测面积、编辑、删除，界面全中文）
        map.pm.addControls({
          position: 'topright',
          drawCircle: false,
          drawMarker: false,
          drawCircleMarker: false,
          drawPolyline: true,
          drawPolygon: true,
          editMode: true,
          dragMode: true,
          cutPolygon: false,
          removalMode: true
        });
        // 修正面积弹窗显示逻辑
        map.on('pm:create', function(e) {
          clearMeasureLabels();
          var layer = e.layer;
          if (layer instanceof L.Polyline && !(layer instanceof L.Polygon)) {
            var len = L.GeometryUtil.length(layer);
            layer.bindPopup('总长度：' + formatLength(len)).openPopup();
          } else if (layer instanceof L.Polygon) {
            var area = getPolygonArea(layer.getLatLngs()[0]);
            layer.bindPopup('总面积：' + formatArea(area)).openPopup();
            addMeasureLabel(layer);
          }
        });
        map.on('pm:edit', function(e) {
          if (e.layer && e.layer.eachLayer) {
            e.layer.eachLayer(function(l) { if (l instanceof L.Polygon) addMeasureLabel(l); });
          } else if (e.layer && e.layer instanceof L.Polygon) {
            addMeasureLabel(e.layer);
          }
        });
        map.on('pm:remove', function(e) {
          if (e.layer instanceof L.Polygon) {
            removeMeasureLabel(e.layer);
          }
        });

        // ========== 测量label功能 ========== //
        // 工具函数：计算折线中点
        function getPolylineMidLatLng(latlngs) {
          let total = 0, segLens = [];
          for (let i = 1; i < latlngs.length; i++) {
            let seg = latlngs[i-1].distanceTo(latlngs[i]);
            segLens.push(seg);
            total += seg;
          }
          let half = total / 2, acc = 0;
          for (let i = 1; i < latlngs.length; i++) {
            if (acc + segLens[i-1] >= half) {
              let remain = half - acc;
              let p1 = latlngs[i-1], p2 = latlngs[i];
              let ratio = remain / segLens[i-1];
              return L.latLng(
                p1.lat + (p2.lat - p1.lat) * ratio,
                p1.lng + (p2.lng - p1.lng) * ratio
              );
            }
            acc += segLens[i-1];
          }
          return latlngs[0];
        }
        // turf.js 计算多边形面积（平方米）
        function getPolygonArea(latlngs) {
          const coords = latlngs.map(ll => [ll.lng, ll.lat]);
          if (coords.length > 0 && (coords[0][0] !== coords[coords.length-1][0] || coords[0][1] !== coords[coords.length-1][1])) {
            coords.push(coords[0]);
          }
          const polygon = turf.polygon([[...coords]]);
          return turf.area(polygon);
        }
        // 存储测量label，便于后续清理/更新
        let measureLabels = new Map();
        function getPolygonCentroid(latlngs) {
          let pts = latlngs[0] ? latlngs[0] : latlngs;
          if (!pts || pts.length < 3) return null; // 新增：顶点数不足不计算
          let x = 0, y = 0, area = 0;
          for (let i = 0, j = pts.length - 1; i < pts.length; j = i++) {
            let f = pts[j].lat * pts[i].lng - pts[i].lat * pts[j].lng;
            x += (pts[j].lat + pts[i].lat) * f;
            y += (pts[j].lng + pts[i].lng) * f;
            area += f;
          }
          area = area / 2;
          if (area === 0) return pts[0];
          x = x / (6 * area);
          y = y / (6 * area);
          return L.latLng(x, y);
        }
        function addMeasureLabel(layer) {
          removeMeasureLabel(layer);
          let tooltip, text = '';
          if (layer instanceof L.Polygon) {
            let latlngs = layer.getLatLngs();
            if (!latlngs[0] || latlngs[0].length < 3) return; // 新增：顶点数不足不添加标签
            let area = getPolygonArea(latlngs[0]);
            text = '总面积：' + formatArea(area);
            let centroid = getPolygonCentroid(latlngs[0]);
            if (!centroid) return; // 新增：质心无效不添加
            tooltip = L.tooltip({permanent:true, direction:'center', className:'measure-label-tooltip'}).setContent(text).setLatLng(centroid);
            tooltip.addTo(map);
          }
          if (tooltip) measureLabels.set(layer._leaflet_id, tooltip);
        }
        function removeMeasureLabel(layer) {
          let t = measureLabels.get(layer._leaflet_id);
          if (t) { map.removeLayer(t); measureLabels.delete(layer._leaflet_id); }
        }
        function updateAllMeasureLabels() {
          map.eachLayer(function(layer) {
            if (layer.pm && (layer instanceof L.Polyline || layer instanceof L.Polygon)) {
              addMeasureLabel(layer);
            }
          });
        }
        // 监听测量创建
        map.on('pm:create', function(e) {
          addMeasureLabel(e.layer);
        });
        // 监听测量编辑
        map.on('pm:edit', function(e) {
          if (e.layer && e.layer.eachLayer) {
            e.layer.eachLayer(function(l) { addMeasureLabel(l); });
          } else if (e.layer) {
            addMeasureLabel(e.layer);
          }
        });
        // 监听测量删除
        map.on('pm:remove', function(e) {
          removeMeasureLabel(e.layer);
        });
        // 页面加载后自动为已有测量图层加label
        setTimeout(updateAllMeasureLabels, 800);

        // 自动生成地名到经纬度映射表（由GeoJSON数据生成）
        const campusPlaceMap = {
          '张亮麻辣烫(山西工程技术学院店)': [37.881778584000074, 113.59888782500002],
          '山西工程技术学院学聚苑餐厅': [37.88486309700005, 113.60156442000005],
          '美食美客砂锅菜土豆粉店(学院店)': [37.88222413900007, 113.6003247970001],
          '山西工程技术学院梦清苑餐厅': [37.88182363900006, 113.59874581200006],
          '学聚苑水果店': [37.88461574300004, 113.6022353830001],
          '菜鸟驿站(长泉南路店)': [37.88209618700006, 113.60014281500003],
          '校园文印店': [37.88189319900005, 113.60001784000008],
          '山西工程技术学院体育馆': [37.88263412100008, 113.60055474300009],
          '山西工程技术学院东体育场(足球场)': [37.88317458800003, 113.60200658000008],
          '东操场(足球场)': [37.88309261000006, 113.60192759800009],
          '山西工程技术学院崇德公寓': [37.88576199400006, 113.60214625700007],
          '山西工程技术学院润泽园': [37.88105412600004, 113.59980893900001],
          '思贤楼': [37.88143719000004, 113.60218476700004],
          '山西工程技术学院尚能公寓': [37.88266179900006, 113.59872171100005],
          '研途考研': [37.88555712500005, 113.6017833190001],
          '山西工程技术学院图书馆二号楼': [37.880813371000045, 113.59899994600005],
          '山西工程技术学院-实验实训中心3号': [37.88076745800004, 113.60132992500007],
          '学院停车场': [37.881446571000026, 113.59874585700004]
        };

        // 地名别名映射（可自行扩充）
        const campusPlaceAlias = {
          '梦清苑餐厅': '山西工程技术学院梦清苑餐厅',
          '学聚苑餐厅': '山西工程技术学院学聚苑餐厅',
          '东体育场': '山西工程技术学院东体育场(足球场)',
          '崇德公寓': '山西工程技术学院崇德公寓',
          '润泽园': '山西工程技术学院润泽园',
          '尚能公寓': '山西工程技术学院尚能公寓',
          '图书馆二号楼': '山西工程技术学院图书馆二号楼',
          '实验实训中心3号': '山西工程技术学院-实验实训中心3号',
          // 可继续扩充
        };

        // 支持模糊匹配和别名的地名解析
        function resolvePlace(name, callback) {
          // 先查别名
          if (campusPlaceAlias[name]) name = campusPlaceAlias[name];
          // 精确匹配
          if (campusPlaceMap[name]) {
            callback({lat: campusPlaceMap[name][0], lng: campusPlaceMap[name][1]});
            return;
          }
          // 模糊匹配（包含关系，忽略大小写）
          let found = null;
          let lower = name.toLowerCase();
          for (let key in campusPlaceMap) {
            if (key.toLowerCase().includes(lower)) {
              found = key;
              break;
            }
          }
          if (found) {
            callback({lat: campusPlaceMap[found][0], lng: campusPlaceMap[found][1]});
            return;
          }
          // 推荐最接近的地名
          let suggestions = Object.keys(campusPlaceMap).filter(k => {
            let lkey = k.toLowerCase();
            return lkey.indexOf(lower[0]) !== -1 || lkey.indexOf(lower.slice(-1)) !== -1;
          });
          if (suggestions.length > 0) {
            alert('未找到该地名，您可以试试：\n' + suggestions.slice(0,5).join('\n'));
          } else {
            alert('未找到该地名，请用地图点选或输入标准地名。');
          }
          callback(null);
        }

        // ========== 地名自动补全下拉建议 ========== //
        function createAutocomplete(input) {
          let acList = document.createElement('div');
          acList.className = 'autocomplete-list';
          acList.style.position = 'absolute';
          acList.style.zIndex = 9999;
          acList.style.background = '#fff';
          acList.style.border = '1px solid #ddd';
          acList.style.borderRadius = '6px';
          acList.style.boxShadow = '0 2px 8px rgba(0,0,0,0.08)';
          acList.style.maxHeight = '180px';
          acList.style.overflowY = 'auto';
          acList.style.minWidth = input.offsetWidth + 'px';
          acList.style.fontSize = '15px';
          acList.style.display = 'none';
          document.body.appendChild(acList);

          function updateList() {
            let val = input.value.trim().toLowerCase();
            if (!val) { acList.style.display = 'none'; return; }
            let allNames = Object.keys(campusPlaceMap).concat(Object.keys(campusPlaceAlias));
            let shown = [];
            for (let name of allNames) {
              if (name.toLowerCase().includes(val) && shown.indexOf(name) === -1) shown.push(name);
              if (shown.length >= 8) break;
            }
            if (shown.length === 0) { acList.style.display = 'none'; return; }
            acList.innerHTML = '';
            shown.forEach((name, idx) => {
              let item = document.createElement('div');
              item.className = 'autocomplete-item';
              item.style.padding = '7px 14px';
              item.style.cursor = 'pointer';
              item.style.borderBottom = '1px solid #f0f0f0';
              item.innerHTML = name;
              item.onmousedown = function(e) {
                e.preventDefault();
                input.value = name;
                acList.style.display = 'none';
                input.dispatchEvent(new Event('input'));
              };
              acList.appendChild(item);
            });
            let rect = input.getBoundingClientRect();
            acList.style.left = rect.left + 'px';
            acList.style.top = (rect.bottom + window.scrollY) + 'px';
            acList.style.minWidth = rect.width + 'px';
            acList.style.display = 'block';
          }

          input.addEventListener('input', updateList);
          input.addEventListener('focus', updateList);
          input.addEventListener('blur', function() { setTimeout(()=>acList.style.display='none', 150); });
          // 键盘上下选择
          let idx = -1;
          input.addEventListener('keydown', function(e) {
            let items = acList.querySelectorAll('.autocomplete-item');
            if (acList.style.display === 'block' && items.length > 0) {
              if (e.key === 'ArrowDown') {
                idx = (idx + 1) % items.length;
                items.forEach((it,i)=>it.style.background=i===idx?'#e3f2fd':'#fff');
                e.preventDefault();
              } else if (e.key === 'ArrowUp') {
                idx = (idx - 1 + items.length) % items.length;
                items.forEach((it,i)=>it.style.background=i===idx?'#e3f2fd':'#fff');
                e.preventDefault();
              } else if (e.key === 'Enter' && idx >= 0) {
                input.value = items[idx].innerText;
                acList.style.display = 'none';
                input.dispatchEvent(new Event('input'));
                e.preventDefault();
              }
            }
          });
        }
        // 自动为路径规划面板的输入框启用自动补全
        setTimeout(function() {
          document.querySelectorAll('.leaflet-routing-container input').forEach(createAutocomplete);
        }, 1200);
        // 自动补全样式
        const style = document.createElement('style');
        style.innerHTML = `.autocomplete-list::-webkit-scrollbar{width:6px;background:#f5f5f5}.autocomplete-list::-webkit-scrollbar-thumb{background:#e0e0e0;border-radius:3px}.autocomplete-item:hover{background:#e3f2fd}`;
        document.head.appendChild(style);

        // ========== 虚线路径绘制 ========== //
        let tempRouteLine = null;
        let tempRouteLabel = null;
        let tempStartMarker = null;
        let tempEndMarker = null;
        let isQuickSetting = false;
        
        function drawTempRouteLine(start, end, mode) {
          if (tempRouteLine) { map.removeLayer(tempRouteLine); tempRouteLine = null; }
          if (tempRouteLabel) { map.removeLayer(tempRouteLabel); tempRouteLabel = null; }
          if (roadPathLine) { map.removeLayer(roadPathLine); roadPathLine = null; }
          tempRouteLine = L.polyline([start, end], {
            color: '#8e24aa', // 紫色
            weight: 5,
            opacity: 0.8,
            dashArray: '10 10',
            lineCap: 'round',
            lineJoin: 'round'
          }).addTo(map);
          // 计算距离并显示标签
          const dist = map.distance(start, end);
          let text = (mode ? mode + ' | ' : '') + (dist < 1000 ? `全长：${dist.toFixed(1)} 米` : `全长：${(dist/1000).toFixed(3)} 千米`);
          // 计算中点
          const mid = L.latLng((start.lat+end.lat)/2, (start.lng+end.lng)/2);
          tempRouteLabel = L.tooltip({permanent:true, direction:'center', className:'measure-label-tooltip'})
            .setContent(text).setLatLng(mid).addTo(map);
          // 新增：显示沿道路最短路径
          showRoadPath(start, end);
          // 起点终点marker颜色
          if (tempStartMarker) map.removeLayer(tempStartMarker);
          if (tempEndMarker) map.removeLayer(tempEndMarker);
          tempStartMarker = L.marker(start, {
            icon: L.divIcon({
              className: 'start-marker',
              html: '<div style="background:#009688;width:20px;height:20px;border-radius:50%;border:3px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.3);"></div>',
              iconSize: [20, 20],
              iconAnchor: [10, 10]
            })
          }).addTo(map).bindPopup('起点').openPopup();
          tempEndMarker = L.marker(end, {
            icon: L.divIcon({
              className: 'end-marker',
              html: '<div style="background:#d32f2f;width:20px;height:20px;border-radius:50%;border:3px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.3);"></div>',
              iconSize: [20, 20],
              iconAnchor: [10, 10]
            })
          }).addTo(map).bindPopup('终点').openPopup();
        }
        
        function clearQuickRoute() {
          if (tempRouteLine) { map.removeLayer(tempRouteLine); tempRouteLine = null; }
          if (tempRouteLabel) { map.removeLayer(tempRouteLabel); tempRouteLabel = null; }
          if (tempStartMarker) { map.removeLayer(tempStartMarker); tempStartMarker = null; }
          if (tempEndMarker) { map.removeLayer(tempEndMarker); tempEndMarker = null; }
          isQuickSetting = false;
        }

        // 快速设置起终点功能
        function initQuickSetButton() {
          var quickSetBtn = document.getElementById('quickSetBtn');
          if (quickSetBtn) {
            quickSetBtn.onclick = function() {
              if (isQuickSetting) {
                // 如果正在设置中，取消设置
                clearQuickRoute();
                map.off('click', onMapClick);
                // 解绑所有点的临时事件
                if(window.geoLayer) window.geoLayer.eachLayer(l=>l.off('click', onMarkerClick));
                if(window.userMarkers) window.userMarkers.forEach(m=>m && m.off('click', onMarkerClick));
                quickSetBtn.textContent = '📍 快速设置起终点';
                quickSetBtn.style.background = '#1976d2';
                alert('已取消快速设置');
                return;
              }
              
              // 开始设置
              isQuickSetting = true;
              quickSetBtn.textContent = '❌ 取消设置';
              quickSetBtn.style.background = '#f44336';
              alert('请在地图上依次点击起点和终点（支持步行、骑行或开车，仅为模拟直线距离，不代表真实道路导航）\n点击第一个点设为起点（绿色），点击第二个点设为终点（红色）');
              
              let clickCount = 0;
              let startPoint = null, endPoint = null;
              
              function finishQuickSet() {
                map.off('click', onMapClick);
                if(window.geoLayer) window.geoLayer.eachLayer(l=>l.off('click', onMarkerClick));
                if(window.userMarkers) window.userMarkers.forEach(m=>m && m.off('click', onMarkerClick));
                isQuickSetting = false;
                quickSetBtn.textContent = '📍 快速设置起终点';
                quickSetBtn.style.background = '#1976d2';
                if (tempStartMarker) tempStartMarker.closePopup();
                if (tempEndMarker) tempEndMarker.closePopup();
              }
              
              function handlePoint(latlng, isMarker) {
                if (clickCount === 0) {
                  startPoint = latlng;
                  if (tempStartMarker) map.removeLayer(tempStartMarker);
                  tempStartMarker = L.marker(startPoint, {
                    icon: L.divIcon({
                      className: 'start-marker',
                      html: '<div style="background:#009688;width:20px;height:20px;border-radius:50%;border:3px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.3);"></div>',
                      iconSize: [20, 20],
                      iconAnchor: [10, 10]
                    })
                  }).addTo(map).bindPopup('起点').openPopup();
                  clickCount++;
                  setTimeout(() => {
                    if (tempStartMarker) {
                      tempStartMarker.closePopup();
                      tempStartMarker.bindPopup('起点已设置，请点击终点').openPopup();
                    }
                  }, 1000);
                } else if (clickCount === 1) {
                  endPoint = latlng;
                  if (tempEndMarker) map.removeLayer(tempEndMarker);
                  tempEndMarker = L.marker(endPoint, {
                    icon: L.divIcon({
                      className: 'end-marker',
                      html: '<div style="background:#d32f2f;width:20px;height:20px;border-radius:50%;border:3px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.3);"></div>',
                      iconSize: [20, 20],
                      iconAnchor: [10, 10]
                    })
                  }).addTo(map).bindPopup('终点').openPopup();
                  clickCount++;
                  setTimeout(function() {
                    // 新增：选择出行方式
                    showModeDialog(function(mode) {
                      if (confirm('起终点已设置完成！\n\n起点：' + startPoint.lat.toFixed(6) + ', ' + startPoint.lng.toFixed(6) + '\n终点：' + endPoint.lat.toFixed(6) + ', ' + endPoint.lng.toFixed(6) + '\n本路径为' + mode + '的模拟最短直线，仅供参考。\n\n是否画出最短路径？')) {
                        drawTempRouteLine(startPoint, endPoint, mode);
                      }
                      finishQuickSet();
                    });
                  }, 500);
                }
              }
              
              function onMapClick(e) { handlePoint(e.latlng, false); }
              function onMarkerClick(e) { L.DomEvent.stopPropagation(e); handlePoint(e.latlng, true); }
              
              map.on('click', onMapClick);
              if(window.geoLayer) window.geoLayer.eachLayer(l=>l.on('click', onMarkerClick));
              if(window.userMarkers) window.userMarkers.forEach(m=>m && m.on('click', onMarkerClick));
            };
          }
        }
        
        // 页面加载完成后初始化快速设置按钮
        setTimeout(initQuickSetButton, 500);
        
        // 初始化清除路径按钮
        function initClearRouteButton() {
          var clearRouteBtn = document.getElementById('clearRouteBtn');
          if (clearRouteBtn) {
            clearRouteBtn.onclick = function() {
              clearQuickRoute();
              if (roadPathLine) { map.removeLayer(roadPathLine); roadPathLine = null; }
              alert('路径已清除');
            };
          }
        }
        
        setTimeout(initClearRouteButton, 500);
        
        // 优化侧边栏按钮和图表间距，避免遮挡
        var sidePanel = document.getElementById('side-panel');
        sidePanel.style.gap = '14px';
        // 统一按钮宽度和分组
        var btns = sidePanel.querySelectorAll('button');
        btns.forEach(function(btn){ 
          btn.style.width = '100%'; 
          btn.style.marginBottom = '10px'; 
        });

        // ========== 图例控件 ========== //
        L.Control.Legend = L.Control.extend({
            options: { position: 'bottomleft' },
            onAdd: function(map) {
                var div = L.DomUtil.create('div', 'leaflet-control legend');
                div.innerHTML = `
                  <div class="legend-title">图例</div>
                  <div class="legend-item"><span class="legend-dot canteen"></span><span class="legend-label">食堂</span></div>
                  <div class="legend-item"><span class="legend-dot dorm"></span><span class="legend-label">宿舍</span></div>
                  <div class="legend-item"><span class="legend-dot teach"></span><span class="legend-label">教学楼</span></div>
                  <div class="legend-item"><span class="legend-dot start-custom"></span><span class="legend-label">起点（深绿色）</span></div>
                  <div class="legend-item"><span class="legend-dot end-custom"></span><span class="legend-label">终点（深红色）</span></div>
                  <div class="legend-item"><span class="legend-line"></span><span class="legend-label">虚线路径（紫色）</span></div>
                  <div class="legend-item"><span style="display:inline-block;width:28px;height:0;border-top:4px solid #43a047;vertical-align:middle;margin:0 7px 0 0;"></span><span class="legend-label">最短路径（绿色）</span></div>
                  <div class="legend-item"><span style="display:inline-block;width:16px;height:16px;border-radius:50%;background:#ffeb3b;border:3px solid #fbc02d;margin-right:7px;"></span><span class="legend-label">选址分析点（黄色）</span></div>
                `;
                return div;
            }
        });
        map.addControl(new L.Control.Legend());

        // 动态显示测量距离/面积（每个点和测量完成后弹窗）
        function formatLength(m) {
          if (m < 1000) return m.toFixed(2) + ' 米';
          return (m / 1000).toFixed(3) + ' 千米';
        }
        function formatArea(m2) {
          if (m2 < 10000) return m2.toFixed(2) + ' 平方米';
          return (m2 / 10000).toFixed(3) + ' 公顷';
        }
        // 清除所有测量临时label
        function clearMeasureLabels() {
          map.eachLayer(function(layer) {
            if (layer._measureLabel) map.removeLayer(layer);
          });
        }
        // 路径方式选择弹窗逻辑
        function showModeDialog(callback) {
          const modal = document.getElementById('customModal');
          // 动态生成内容
          document.getElementById('modalTitle').innerText = '请选择出行方式';
          document.getElementById('modalBody').innerHTML = `
            <select id="modalType" style="font-size:15px;padding:8px 12px;border:1px solid #1976d2;border-radius:8px;margin-bottom:16px;outline:none;width:100%;max-width:220px;">
              <option value="步行">步行</option>
              <option value="骑行">骑行</option>
              <option value="开车">开车</option>
            </select>
          `;
          document.getElementById('modalFooter').innerHTML = `
            <button id="modalOk" class="modal-btn">确定</button>
            <button id="modalCancel" class="modal-btn cancel">取消</button>
          `;
          const select = document.getElementById('modalType');
          modal.style.display = 'flex';
          select.value = '步行';
          function close(result) {
            modal.style.display = 'none';
            document.getElementById('modalOk').onclick = null;
            document.getElementById('modalCancel').onclick = null;
            select.onkeydown = null;
            callback(result);
          }
          document.getElementById('modalOk').onclick = function() { close(select.value); };
          document.getElementById('modalCancel').onclick = function() { close(null); };
          select.onkeydown = function(e) {
            if (e.key === 'Enter') close(select.value);
            if (e.key === 'Escape') close(null);
          };
          select.focus();
        }

        // ========== 加载并显示校园道路 ========== //
        let roadData = null;
        let roadLayer = null;
        fetch('../data/Line_Export_Output.json')
          .then(res => res.json())
          .then(data => {
            roadData = data;
            roadLayer = L.geoJSON(data, {
              style: { color: '#1976d2', weight: 4, opacity: 0.7 }
            }).addTo(map);
          });

        // ========== 路网建模与最短路径算法 ========== //
        // 1. 解析所有LineString为节点和边
        function buildRoadGraph(roadData) {
          const nodes = [];
          const nodeMap = new Map(); // key: 'lng,lat' value: index
          const edges = [];
          function coordKey(coord) { return coord[0] + ',' + coord[1]; }
          // 收集所有节点
          roadData.features.forEach(f => {
            let coords = f.geometry.coordinates;
            for (let i = 0; i < coords.length; i++) {
              let key = coordKey(coords[i]);
              if (!nodeMap.has(key)) {
                nodeMap.set(key, nodes.length);
                nodes.push(coords[i]);
              }
            }
          });
          // 建立边
          roadData.features.forEach(f => {
            let coords = f.geometry.coordinates;
            for (let i = 0; i < coords.length - 1; i++) {
              let a = nodeMap.get(coordKey(coords[i]));
              let b = nodeMap.get(coordKey(coords[i+1]));
              let dist = turf.distance(turf.point(coords[i]), turf.point(coords[i+1]));
              edges.push({from: a, to: b, weight: dist});
              edges.push({from: b, to: a, weight: dist}); // 无向
            }
          });
          // 邻接表
          const adj = Array(nodes.length).fill(0).map(() => []);
          edges.forEach(e => { adj[e.from].push({to: e.to, weight: e.weight}); });
          return {nodes, adj};
        }

        // 2. 找到最近节点
        function findNearestNode(latlng, nodes) {
          let minDist = Infinity, idx = -1;
          for (let i = 0; i < nodes.length; i++) {
            let d = turf.distance(turf.point([latlng.lng, latlng.lat]), turf.point(nodes[i]));
            if (d < minDist) { minDist = d; idx = i; }
          }
          return idx;
        }

        // 3. Dijkstra最短路径
        function dijkstra(adj, start, end) {
          const n = adj.length;
          const dist = Array(n).fill(Infinity);
          const prev = Array(n).fill(-1);
          const visited = Array(n).fill(false);
          dist[start] = 0;
          for (let i = 0; i < n; i++) {
            let u = -1;
            for (let j = 0; j < n; j++) {
              if (!visited[j] && (u === -1 || dist[j] < dist[u])) u = j;
            }
            if (dist[u] === Infinity) break;
            visited[u] = true;
            for (const e of adj[u]) {
              if (dist[e.to] > dist[u] + e.weight) {
                dist[e.to] = dist[u] + e.weight;
                prev[e.to] = u;
              }
            }
          }
          // 回溯路径
          let path = [];
          for (let at = end; at !== -1; at = prev[at]) path.push(at);
          path.reverse();
          if (path[0] !== start) return [];
          return path;
        }

        // ========== 路径规划集成 ========== //
        let roadGraph = null;
        let roadPathLine = null;
        function showRoadPath(startLatLng, endLatLng) {
          if (!roadData) return;
          if (!roadGraph) roadGraph = buildRoadGraph(roadData);
          const {nodes, adj} = roadGraph;
          const startIdx = findNearestNode(startLatLng, nodes);
          const endIdx = findNearestNode(endLatLng, nodes);
          const pathIdx = dijkstra(adj, startIdx, endIdx);
          if (roadPathLine) { map.removeLayer(roadPathLine); roadPathLine = null; }
          if (pathIdx.length > 1) {
            const latlngs = pathIdx.map(i => [nodes[i][1], nodes[i][0]]); // [lat, lng]
            roadPathLine = L.polyline(latlngs, {color:'#43a047',weight:6,opacity:0.95}).addTo(map);
          }
        }

        // 选址分析功能
        var siteAnalysisMode = false;
        var siteMarker = null;
        document.getElementById('siteAnalysisBtn').onclick = function() {
          if (siteAnalysisMode) return;
          siteAnalysisMode = true;
          this.innerText = '请在地图上点选候选点...';
          this.disabled = true;
          showCustomModal('选址分析', '请在地图上点击一个候选点，系统将分析其与主要设施的空间关系。');
          map.on('click', siteAnalysisClickHandler);
        };
        function siteAnalysisClickHandler(e) {
          var latlng = e.latlng;
          if (siteMarker) map.removeLayer(siteMarker);
          siteMarker = L.circleMarker(latlng, {
            radius: 12,
            fillColor: '#ffeb3b',
            color: '#fbc02d',
            weight: 3,
            opacity: 1,
            fillOpacity: 0.85
          }).addTo(map);
          // 计算与教学楼、宿舍、食堂的最近距离
          var nearest = { '教学楼': {dist: Infinity, name: ''}, '宿舍': {dist: Infinity, name: ''}, '食堂': {dist: Infinity, name: ''} };
          if (window.geoLayer) {
            window.geoLayer.eachLayer(function(layer) {
              if (!layer.feature || !layer.feature.properties) return;
              var type = (function(feature) {
                const f8 = feature.properties && feature.properties.Field8 ? feature.properties.Field8 : '';
                if (f8.includes('餐饮') || f8.includes('食堂') || f8.includes('餐厅')) return '食堂';
                if (f8.includes('宿舍')) return '宿舍';
                if (f8.includes('教学楼') || f8.includes('学校') || f8.includes('图书馆')) return '教学楼';
                return '其他';
              })(layer.feature);
              if (!nearest[type]) return;
              var ll = layer.getLatLng();
              var d = map.distance(latlng, ll);
              if (d < nearest[type].dist) {
                nearest[type].dist = d;
                nearest[type].name = layer.feature.properties.Field1 || '';
              }
            });
          }
          // 保存分析结果到marker属性，便于后续点击弹窗
          siteMarker.analysisInfo = {
            latlng: latlng,
            nearest: JSON.parse(JSON.stringify(nearest))
          };
          siteMarker.on('click', function() {
            showSiteAnalysisResult(this.analysisInfo);
          });
          showSiteAnalysisResult(siteMarker.analysisInfo);
          // 退出模式
          map.off('click', siteAnalysisClickHandler);
          siteAnalysisMode = false;
          document.getElementById('siteAnalysisBtn').innerText = '选址分析';
          document.getElementById('siteAnalysisBtn').disabled = false;
        }
        function showSiteAnalysisResult(info) {
          var latlng = info.latlng;
          var nearest = info.nearest;
          var html = '<div>已选点坐标：<br>纬度 ' + latlng.lat.toFixed(6) + '<br>经度 ' + latlng.lng.toFixed(6) + '</div>';
          html += '<table style="margin-top:10px;font-size:15px;width:100%;text-align:left;">';
          html += '<tr><th>类别</th><th>最近设施</th><th>距离</th></tr>';
          ['教学楼','宿舍','食堂'].forEach(function(type) {
            html += '<tr><td>' + type + '</td><td>' + (nearest[type].name||'-') + '</td><td>' + (nearest[type].dist!==Infinity ? nearest[type].dist.toFixed(1)+'米' : '-') + '</td></tr>';
          });
          html += '</table>';
          html += '<div style="text-align:right;margin-top:16px;"><button class="modal-btn" onclick="removeSiteMarker()">删除分析点</button><button class="modal-btn cancel" onclick="document.getElementById(\'customModal\').style.display=\'none\'">关闭</button></div>';
          showCustomModal('选址分析结果', html, false);
        }
        window.removeSiteMarker = function() {
          if (siteMarker) { map.removeLayer(siteMarker); siteMarker = null; }
          document.getElementById('customModal').style.display = 'none';
        };
        // 修改showCustomModal支持不自动生成关闭按钮
        function showCustomModal(title, body, autoCloseBtn) {
          document.getElementById('modalTitle').innerHTML = title;
          document.getElementById('modalBody').innerHTML = body;
          document.getElementById('customModal').style.display = 'flex';
          if (autoCloseBtn !== false) {
            document.getElementById('modalFooter').innerHTML = '<button class="modal-btn" onclick="document.getElementById(\'customModal\').style.display=\'none\'">关闭</button>';
          } else {
            document.getElementById('modalFooter').innerHTML = '';
          }
        }
    </script>
</body>
</html>
